home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 1 / Meeting Pearls Vol 1 (1994).iso / installed_progs / util / pgp / pgpamiga / source / pgp_todo.lha / idea.asm < prev   
Encoding:
Assembly Source File  |  1993-08-07  |  34.3 KB  |  964 lines

  1. ; This code performs the core operation that computes the MD5
  2. ; message digest of a bunch of longwords.  MD5 is defined over
  3. ; longwords; when it must be performed over smaller units (bytes
  4. ; or bits), they are packed into longwords little-endian.
  5. ; The byteReverse function swaps the bytes around in a buffer of
  6. ; longwords for this purpose.
  7.  
  8. ; You start with a 4-long buffer initialized to the magic values
  9. ; $67452301, $efcdab89, $98badcfe, $10325476
  10. ; And then, for each 16-longword chunk of input, the Transform()
  11. ; function is called, which alters the 4-longword buffer in-place
  12. ; based on the next 16 longwords of input.
  13. ;
  14. ; At the end of the input, it is padded with a 1 bit, and then as
  15. ; many 0 bits as are needed to come 2 longwords short of a full
  16. ; 16-longword chunk.  The last two longwords are a 64-bit count of the
  17. ; number of bits in the input, exclusive of padding, least signficant
  18. ; longword first.
  19. ;
  20. ; After that trailer has been fed through Transform(), the contents
  21. ; of the buffer are the MD5 checksum.  If they must be expressed as bytes,
  22. ; they should be presented in little-endian order.
  23.  
  24. ; Byte-swap a buffer full of longs
  25.  
  26.         xdef    _byteReverse
  27. _byteReverse:
  28. ; args: buf, longs
  29.         move.l  4(sp),a0        ; Buf
  30.         move.w  10(sp),d0       ; Longs
  31.         subq.w  #1,d0           ; We assume this is never 0 to start with
  32. revloop:
  33.         move.l  (a0),d1
  34.         ror.w   #8,d1
  35.         swap    d1
  36.         ror.w   #8,d1
  37.         move.l  d1,(a0)+
  38.  
  39.         dbra    d0,revloop
  40.  
  41.         rts
  42.  
  43. ; Macros needed by the MD5 transformation code
  44.  
  45. ; rotl  r1,bits - rotate register r1 left the given number of bits
  46. rotl    macro   ; args: reg, bits
  47.     ifc \2,''   ; = 0
  48.         mexit
  49.     endc
  50.     ifle \2-8   ; <= 8
  51.         rol.l   #\2,\1
  52.         mexit
  53.     endc
  54.     ifge \2-24  ; >= 24
  55.         ror.l   #32-\2,\1
  56.         mexit
  57.     endc
  58.         swap    \1
  59.     iflt \2-16  ; < 16
  60.         ror.l   #16-\2,\1
  61.         mexit
  62.     endc
  63.     ifgt \2-16  ; > 16
  64.         rol.l   #\2-16,\1
  65.         mexit
  66.     endc
  67.         endm
  68. ; Cycles taken:
  69. ;  0 -  0   4 - 16   8 - 24  12 - 20  16 -  4  20 - 20  24 - 24  28 - 16
  70. ;  1 - 10   5 - 18   9 - 26  13 - 18  17 - 14  21 - 22  25 - 22  29 - 14
  71. ;  2 - 12   6 - 20  10 - 24  14 - 16  18 - 16  22 - 24  26 - 20  30 - 12
  72. ;  3 - 14   7 - 22  11 - 22  15 - 14  19 - 18  23 - 26  27 - 18  31 - 10
  73. ; MD5 uses 4 rotations each in the amounts 4, 5, 6, 7, 9, 10, 11, 12,
  74. ; 14, 15, 16, 17, 20, 21, 22, 23.  The total timing for each of
  75. ; those is 16+18+20+22 + 26+24+22+20 + 16+14+4+14 + 20+22+24+26 cycles,
  76. ; 4*19 + 4*23 + 4*12 + 4*23 = 4 * 77 = 308 cycles, or 1232 for the 4.
  77.  
  78. ; Macros to compute the four boolean functions used in MD5
  79. ; Each one takes three arguments (x, y, z) and returns a result in d0.
  80.  
  81. f1      macro   ; d0 = (x & y) | (~x & z)
  82.         move.l  \3,d0
  83.         eor.l   \2,d0
  84.         and.l   \1,d0
  85.         eor.l   \3,d0
  86.         endm    ; 4+8+8+8 = 28 cycles
  87.  
  88. f2      macro   ; d0 = (x & z) | (x & ~z)
  89.         f1 \3,\1,\2
  90.         endm    ; 28 cycles
  91.  
  92. f3      macro   ; d0 = x ^ y ^ z
  93.         move.l  \1,d0
  94.         eor.l   \2,d0
  95.         eor.l   \3,d0
  96.         endm    ; 4+8+8 = 20 cycles
  97.  
  98. f4      macro   ; d0 = y ^ (x | ~z)
  99.         move.l  \3,d0
  100.         not.l   d0
  101.         or.l    \1,d0
  102.         eor.l   \2,d0
  103.         endm    ; 4+6+8+8 = 26 cycles
  104.  
  105. ; The total time for these steps is 16 times (28+28+20+26) = 16 * 102 = 1632
  106. ; cycles.
  107.  
  108. ; The basic step in the MD5 computation
  109. ; Note that the current code does not use the constant argument,
  110. ; getitng it from a table instead.  The constants have been left in
  111. ; the source because it's a real pain in the ass to type them all
  112. ; in correctly if changing this macro ever becomes a good idea.
  113.  
  114. md5step macro   ; args: f, w, x, y, z, const, input, shift
  115.         \1      \3,\4,\5        ; f(x, y, z) in d0
  116.         add.l   (a0)+,d0
  117.         add.l   \7,d0
  118.         add.l   d0,\2   ; w += f(x, y, z) + const + input
  119.         rotl    \2,\8   ; w = ROTL(w, shift)
  120.         add.l   \3,\2   ; w += x
  121.         endm    ; f + 14 + 6 + data + 8 + rot + 8 = 36 + f + data + rot cycles
  122. ; In most cases, the data cost is 12 cycles (long with 16-bit offset);
  123. ; values will be subtracted below where it's less.
  124. ; So that's a total of 48 cycles, times 64 is 3072 cycles.
  125.  
  126. ; Okay, the actual code (finally):
  127.  
  128.         xdef    _Transform2
  129. _Transform2:
  130. ; args: uint32 buf[4], uint32 in[16]
  131.         move.l  4(sp),a0        ; buf    16
  132.         move.l  8(sp),a1        ; in     16  32
  133.         movem.l d2-d4,-(sp)     ;        32  64
  134.  
  135.         movem.l (a0),d1-d4      ;        44 108
  136.         lea     md5table(pc),a0 ;         8 116
  137.  
  138.         md5step f1,d1,d2,d3,d4,$d76aa478,(a1)+,7
  139.         md5step f1,d4,d1,d2,d3,$e8c7b756,(a1)+,12
  140.         md5step f1,d3,d4,d1,d2,$242070db,(a1)+,17
  141.         md5step f1,d2,d3,d4,d1,$c1bdceee,(a1)+,22
  142.         md5step f1,d1,d2,d3,d4,$f57c0faf,(a1)+,7
  143.         md5step f1,d4,d1,d2,d3,$4787c62a,(a1)+,12
  144.         md5step f1,d3,d4,d1,d2,$a8304613,(a1)+,17
  145.         md5step f1,d2,d3,d4,d1,$fd469501,(a1)+,22
  146.         md5step f1,d1,d2,d3,d4,$698098d8,(a1)+,7
  147.         md5step f1,d4,d1,d2,d3,$8b44f7af,(a1)+,12
  148.         md5step f1,d3,d4,d1,d2,$ffff5bb1,(a1)+,17
  149.         md5step f1,d2,d3,d4,d1,$895cd7be,(a1)+,22
  150.         md5step f1,d1,d2,d3,d4,$6b901122,(a1)+,7
  151.         md5step f1,d4,d1,d2,d3,$fd987193,(a1)+,12
  152.         md5step f1,d3,d4,d1,d2,$a679438e,(a1)+,17
  153.         md5step f1,d2,d3,d4,d1,$49b40821,(a1),22
  154. ; Subtract 4*16 = 64 cycles for no offsets
  155.  
  156.         md5step f2,d1,d2,d3,d4,$f61e2562,4*1-60(a1),5
  157.         md5step f2,d4,d1,d2,d3,$c040b340,4*6-60(a1),9
  158.         md5step f2,d3,d4,d1,d2,$265e5a51,4*11-60(a1),14
  159.         md5step f2,d2,d3,d4,d1,$e9b6c7aa,4*0-60(a1),20
  160.         md5step f2,d1,d2,d3,d4,$d62f105d,4*5-60(a1),5
  161.         md5step f2,d4,d1,d2,d3,$02441453,4*10-60(a1),9
  162.         md5step f2,d3,d4,d1,d2,$d8a1e681,(a1),14
  163.         md5step f2,d2,d3,d4,d1,$e7d3fbc8,4*4-60(a1),20
  164.         md5step f2,d1,d2,d3,d4,$21e1cde6,4*9-60(a1),5
  165.         md5step f2,d4,d1,d2,d3,$c33707d6,-(a1),9
  166.         md5step f2,d3,d4,d1,d2,$f4d50d87,4*3-56(a1),14
  167.         md5step f2,d2,d3,d4,d1,$455a14ed,4*8-56(a1),20
  168.         md5step f2,d1,d2,d3,d4,$a9e3e905,-(a1),5
  169.         md5step f2,d4,d1,d2,d3,$fcefa3f8,4*2-52(a1),9
  170.         md5step f2,d3,d4,d1,d2,$676f02d9,4*7-52(a1),14
  171.         md5step f2,d2,d3,d4,d1,$8d2a4c8a,-(a1),20
  172. ; Subtract 4+6 = 10 cycles for no offsets
  173.  
  174.         md5step f3,d1,d2,d3,d4,$fffa3942,4*5-48(a1),4
  175.         md5step f3,d4,d1,d2,d3,$8771f681,4*8-48(a1),11
  176.         md5step f3,d3,d4,d1,d2,$6d9d6122,-(a1),16
  177.         md5step f3,d2,d3,d4,d1,$fde5380c,4*14-44(a1),23
  178.         md5step f3,d1,d2,d3,d4,$a4beea44,4*1-44(a1),4
  179.         md5step f3,d4,d1,d2,d3,$4bdecfa9,4*4-44(a1),11
  180.         md5step f3,d3,d4,d1,d2,$f6bb4b60,4*7-44(a1),16
  181.         md5step f3,d2,d3,d4,d1,$bebfbc70,-(a1),23
  182.         md5step f3,d1,d2,d3,d4,$289b7ec6,4*13-40(a1),4
  183.         md5step f3,d4,d1,d2,d3,$eaa127fa,4*0-40(a1),11
  184.         md5step f3,d3,d4,d1,d2,$d4ef3085,4*3-40(a1),16
  185.         md5step f3,d2,d3,d4,d1,$04881d05,4*6-40(a1),23
  186.         md5step f3,d1,d2,d3,d4,$d9d4d039,4*9-40(a1),4
  187.         md5step f3,d4,d1,d2,d3,$e6db99e5,4*12-40(a1),11
  188.         md5step f3,d3,d4,d1,d2,$1fa27cf8,4*15-40(a1),16
  189.         md5step f3,d2,d3,d4,d1,$c4ac5665,4*2-40(a1),23
  190. ; subtract 4 cycles for no offsets
  191.  
  192.         md5step f4,d1,d2,d3,d4,$f4292244,4*0-40(a1),6
  193.         md5step f4,d4,d1,d2,d3,$432aff97,4*7-40(a1),10
  194.         md5step f4,d3,d4,d1,d2,$ab9423a7,4*14-40(a1),15
  195.         md5step f4,d2,d3,d4,d1,$fc93a039,4*5-40(a1),21
  196.         md5step f4,d1,d2,d3,d4,$655b59c3,4*12-40(a1),6
  197.         md5step f4,d4,d1,d2,d3,$8f0ccc92,4*3-40(a1),10
  198.         md5step f4,d3,d4,d1,d2,$ffeff47d,(a1)+,15
  199.         md5step f4,d2,d3,d4,d1,$85845dd1,4*1-44(a1),21
  200.         md5step f4,d1,d2,d3,d4,$6fa87e4f,4*8-44(a1),6
  201.         md5step f4,d4,d1,d2,d3,$fe2ce6e0,4*15-44(a1),10
  202.         md5step f4,d3,d4,d1,d2,$a3014314,4*6-44(a1),15
  203.         md5step f4,d2,d3,d4,d1,$4e0811a1,4*13-44(a1),21
  204.         md5step f4,d1,d2,d3,d4,$f7537e82,4*4-44(a1),6
  205.         md5step f4,d4,d1,d2,d3,$bd3af235,(a1),10
  206.         md5step f4,d3,d4,d1,d2,$2ad7d2bb,4*2-44(a1),15
  207.         md5step f4,d2,d3,d4,d1,$eb86d391,4*9-44(a1),21
  208. ; Subtract 8 cycles for no offsets
  209.  
  210.                                 ;           116
  211.         move.l  16(sp),a0       ;        16 132
  212.         add.l   d1,(a0)+        ;        20 152
  213.         add.l   d2,(a0)+        ;        20 172
  214.         add.l   d3,(a0)+        ;        20 192
  215.         add.l   d4,(a0)+        ;        20 212
  216.  
  217.         movem.l (sp)+,d2-d4     ;        36 248
  218.         rts                     ;        16 264
  219.  
  220. ; So, that's a total of 86 cycles subtracted for no offets, from
  221. ; 264 + 1232 + 1632 + 3072 = 6200 cycles.  The final tally is
  222. ; thus 6114 cycles.
  223.  
  224. ; A table of the Mysterious Constants used by the MD5 computation.
  225. md5table:
  226.         dc.l $d76aa478,$e8c7b756,$242070db,$c1bdceee
  227.         dc.l $f57c0faf,$4787c62a,$a8304613,$fd469501
  228.         dc.l $698098d8,$8b44f7af,$ffff5bb1,$895cd7be
  229.         dc.l $6b901122,$fd987193,$a679438e,$49b40821
  230.  
  231.         dc.l $f61e2562,$c040b340,$265e5a51,$e9b6c7aa
  232.         dc.l $d62f105d,$02441453,$d8a1e681,$e7d3fbc8
  233.         dc.l $21e1cde6,$c33707d6,$f4d50d87,$455a14ed
  234.         dc.l $a9e3e905,$fcefa3f8,$676f02d9,$8d2a4c8a
  235.  
  236.         dc.l $fffa3942,$8771f681,$6d9d6122,$fde5380c
  237.         dc.l $a4beea44,$4bdecfa9,$f6bb4b60,$bebfbc70
  238.         dc.l $289b7ec6,$eaa127fa,$d4ef3085,$04881d05
  239.         dc.l $d9d4d039,$e6db99e5,$1fa27cf8,$c4ac5665
  240.  
  241.         dc.l $f4292244,$432aff97,$ab9423a7,$fc93a039
  242.         dc.l $655b59c3,$8f0ccc92,$ffeff47d,$85845dd1
  243.         dc.l $6fa87e4f,$fe2ce6e0,$a3014314,$4e0811a1
  244.         dc.l $f7537e82,$bd3af235,$2ad7d2bb,$eb86d391
  245.  
  246.         end
  247.  
  248.  
  249. ;;; Crypt2.asm - 68000 assembler versions of heavily-used functions in
  250. ;;;              crypt.c for the IDEA cipher.  By Colin Plumb; not part
  251. ;;;              of the original distribution from ETH Zurich
  252. ;;;              isibee.ethz.ch:pub/simpl/idea.V1.0.tar.Z (129.132.38.1)
  253. ;;;
  254. ;;; No copyright is claimed on this code; it is in the public domain.
  255. ;;; It would be nice if you could give me credit if you use it, but
  256. ;;; the legal definition of "public domain" states that there is no
  257. ;;; legal obligation to do so.
  258.  
  259. ;;; An earlier version of this code is circulating with a copyright notice
  260. ;;; on it; this was due to my mailing out an earlier version without any
  261. ;;; indication of the intended status, so the recipient assumed I claimed
  262. ;;; copyright.  It is, however, incorrect.  And if you want my e-mail
  263. ;;; address, the best one to use for the long term is <colin@nyx.cs.du.edu>.
  264.  
  265. ;;; Now, the original code referenced above provides various encryption
  266. ;;; modes, in particular feedback and chaining modes which have a
  267. ;;; lag of greater than 1.  These are useful only in very specialized
  268. ;;; applications, and for general use the lag factor of 1 is strongest.
  269. ;;; There is no reason for a typical application package to use anything
  270. ;;; else.  In particular, the xpkidea.library which associates a "quality"
  271. ;;; of 100% with a lag factor of 25 is downright dangerous; typical users
  272. ;;; aren't going to be able to come up with 25 fully random initial vectors.
  273.  
  274. ;;; Electronic Code Book (ECB) mode, where you pass each block of plaintext
  275. ;;; through the cipher system, is not very good and should be avoided, as
  276. ;;; repeated plaintext results in repeated ciphertext, which gives information
  277. ;;; away.  Output Feedback (OFB) mode is vulnerable if you reuse keys and
  278. ;;; initial vectors.  In particular, if you encrypt two uncompressed ASCII
  279. ;;; messages with the same key and initial vector, it is not difficult
  280. ;;; (even for a normal user, much less an intelligence agency!) to first,
  281. ;;; read both messages up to the minimum of their two lengths, and second,
  282. ;;; read any other shorter message sent with the same key and initial vector.
  283.  
  284. ;;; The only modes that you should consider are Cipher Block Chaining (CBC)
  285. ;;; and Cipher Feedback (CFB) modes.  CFB has the advantage that the text
  286. ;;; does not have to be a multiple of a block long, and so does not expand
  287. ;;; the text.  It also does not require a decryption routine (or the moral
  288. ;;; equyivalent, InvertIdeaKey, below).  It is recommended for general use.
  289.  
  290. ;;; Where the plaintext blocks are the array x[i] and the ciphertext are y[i],
  291. ;;; IDEA encryption is denoted by IDEA(plain,key) and decryption by
  292. ;;; IIDEA(cipher,key), the modes are as follows:
  293.  
  294. ;;; CBC encrypt: y[i] = IDEA(x[i]^y[i-1], key)
  295. ;;; CBC decrypt: x[i] = y[i-1] ^ IIDEA(y[i], key)
  296. ;;; CFB encrypt: y[i] = x[i] ^ IDEA(y[i-1], key)
  297. ;;; CFB decrypt: x[i] = y[i] ^ IDEA(y[i-1], key)
  298.  
  299. ;;; Both modes require initial vectors y[-1].  This can be a random number,
  300. ;;; or you can set it to a constant (e.g. 0) and make x[0] be a random
  301. ;;; number.  This saves you the effort of storing it somewhere else.
  302.  
  303. ;;; For something like a disk or file encryptor, set it to some unique
  304. ;;; value, like the inode number or disk block number.  This way, identical
  305. ;;; blocks will still be encrypted differently.
  306.  
  307. ;;; Folks, this is a pretty darn good encryption algorithm.  Proving
  308. ;;; that is a lot of work.  Unless you understand that proof, you are
  309. ;;; not competent to "improve" it.  In particular, don't change the
  310. ;;; way a 128-bit key is expanded to a 832-bit working key.  And don't
  311. ;;; think about "fixing" the reversed addition in the last step.  That
  312. ;;; significantly weakens the cipher.  If you don't understand, then
  313. ;;; just take it as evidence that you shouldn't mess with things you
  314. ;;; don't understand.
  315.  
  316. ;;; And don't forget that english text has an average entropy of less
  317. ;;; than 2 bits per character.  That is, you have to compress ASCII by
  318. ;;; 4:1 before it is totally random and can't be further compressed with
  319. ;;; sufficient effort.  So if you want to use a password, it should be 64
  320. ;;; bytes long, not 16.  (It can be shorter if you use a hard-to-remember
  321. ;;; string with lots of nonsense words, FUnNy capitalisation or @dd
  322. ;;; characters.)  You have to hash it down to 128 random bits.  An
  323. ;;; algorithm for that is not supplied.  Exclusive-oring 16-byte blocks
  324. ;;; together does not work well.
  325.  
  326. ;;; Remember, 2^128 is a very large number.  38.5 decimal digits.
  327. ;;; 340,282,366,920,938,463,463,374,607,431,768,211,456.
  328. ;;; 340 thousand million billion trillion million.  Or, equivalently,
  329. ;;; 340 million million million million million million.  That's
  330. ;;; a bit over 27 totally random letters.  But a standard pass phrase,
  331. ;;; even a wierd one, is far from totally random.  For starters, it's
  332. ;;; usually easy to figure out where the blanks go even if they're
  333. ;;; stripped out.  "scramblepatternpipelineyellow" is 29 characters
  334. ;;; long, but nothing like random.  A random string of 27 letters
  335. ;;; looks like "xbrebwcrajhozfepyclvgkchqro".  This was a standard
  336. ;;; pseudo-random number generator; it may look random to you, but
  337. ;;; it's not good enough for high-security applications.
  338.  
  339. ;;; (Okay, so the cycle counts indicate an unhealthy obsession.)
  340. ;;; Multiply takes, according to the 6th edition Motorola MC68000
  341. ;;; manual, 38+2n cycles, where n is the number of bits set in the
  342. ;;; source effective address.  Since the data are random, on average
  343. ;;; 8 of the 16 bits will be set, and multiplies will take 54 cycles
  344. ;;; on average.
  345.  
  346. nofKeyPerRound  equ     6 ; number of used keys per round
  347. nofRound        equ     8 ; number of rounds
  348.  
  349. ; Multiply two numbers in the range of 1..0x10000, modulo 0x10001.
  350. ; 0x10000 is represented as 0.
  351.  
  352. Mult    macro   ; src1, src2, dest, neither source is 0
  353.                 ; dest may equal src2, but not src1 (which is zeroed)
  354.         mulu    %2,%1   ; 54
  355.         move.w  %1,%3   ;  4
  356.         swap    %1      ;  4 %1 now holds high part
  357.         sub.w   %1,%3   ;  4
  358.         moveq   #0,%1   ;  4 does not affect X flag
  359.         addx.w  %1,%3   ;  4
  360.  
  361.         endm            ; 74
  362. ; Code to handle the cases where one argument is 0 = 0x10000 = -1.
  363. ; Negate the other modulo 0x10001, giving 0x10001 - x = 1 - x.
  364. ; In-place and out-of-place versions
  365.  
  366. Invert1 macro   ; dest
  367.         neg.w   %1      ;  4
  368.         addq.w  #1,%1   ;  4
  369.         endm            ;  8
  370.  
  371. Invert2 macro   ; src, dest
  372.         moveq   #1,%2   ;  4
  373.         sub.w   %1,%2   ;  4
  374.         endm            ;  8
  375.  
  376. ; Externally callable version (also a usage example)
  377.  
  378.         xdef    _Mul
  379.         xdef    _Mul2
  380. _Mul:
  381. _Mul2:
  382.         move.w  4(sp),d0        ; 12
  383.         beq.s   Mul_a_is_0      ;  8
  384.         move.w  6(sp),d1        ; 12
  385.         beq.s   Mul_b_is_0      ;  8
  386.         Mult    d1,d0,d0        ; 54 (based on average of 8 bits set)
  387.         rts                     ; 10 = 104 total
  388. Mul_a_is_0:
  389.         Invert2 6(sp),d0
  390.         rts
  391. Mul_b_is_0:
  392.         Invert1 d0
  393.         rts
  394. MulEnd:
  395. ;; The cases where a or b are zero are so rare they don't affect the average
  396. ;; time significantly.
  397.  
  398.  
  399. ; encryption and decryption algorithm IDEA
  400.  
  401. ; void  Idea(u_int16 dataIn[4], u_int16 dataOut[4], u_int16 key[52])
  402.  
  403. ; This performs the core IDEA encryption.  It leaves no sensitive
  404. ; information behind in memory or registers, except for a temporary
  405. ; value from the last KeyMult in d0, which is probably safe to assume will
  406. ; quickly be trashed.
  407.  
  408. ; Modifying this code is NOT recommended for the faint of heart.
  409.  
  410. ; This code is, in a word, *tight*.  Note in particular the use of the low
  411. ; halves of d2-d7 only, to eliminate the overhead of saving and restoring
  412. ; their high halves, the use of d3 as a constant zero source, and a1
  413. ; doubling as a loop counter.  Also note that the exceptional cases in the
  414. ; KeyMult macro have been taken entirely out of line, and there has been
  415. ; some code motion to between KeyMult 5 and 6 so that the branches stay
  416. ; in short range (which they are, barely: offsets of +126 and -126 bytes
  417. ; both occur).
  418.  
  419. ; Unrolling this loop any further would result in the branches going out
  420. ; of short branch range, which would cost more in instruction fetch time
  421. ; than would be saved by the unrolling.  It would also take it out of a
  422. ; 68020's cache.
  423.  
  424. ; Register usage:
  425. ; d0.l - KeyMult temp
  426. ; d1.l - Constant zero
  427. ; d2.w - s2
  428. ; d3.w - s1
  429. ; d4.w - x0
  430. ; d5.w - x2     <- Note reversal
  431. ; d6.w - x1
  432. ; d7.w - x3
  433. ; a0.l - dataIn, dataOut and key pointer limit
  434. ; a1.l - Pointer to current location in expanded key
  435.  
  436. ; KeyMult: Multiply value in register by next available key (pointed at by a1).
  437. ; Requires corresponding MultAux code nearby.
  438.  
  439. KeyMult macro   ; %1 = number, %2 = register
  440.         move.w  %2,d0           ;  4
  441.         beq     Mul%1_a_is_0    ;  8
  442.         mulu    (a1)+,d0        ; 58 (42 if 0)
  443.         beq.s   Mul%1_b_is_0    ;  8
  444.         move.w  d0,%2           ;  4
  445.         swap    d0              ;  4
  446.         sub.w   d0,%2           ;  4
  447.         addx.w  d1,%2           ;  4
  448. Mul%1_done:
  449.         endm                    ; 94 total
  450.  
  451. ; Note: the following cases should occur 1/65536 of the time, however the
  452. ; second, if it occurs, will occur for every block encrypted using the
  453. ; same key, so it is important that it not be significantly slower than the
  454. ; common case.  (It's faster, so all is well.)
  455.  
  456. MultAux macro   ; %1 = number, %2 = register
  457. Mul%1_a_is_0:                   ; 14 move and branch overhead
  458.         move.w  #1,%2           ;  8
  459.         sub.w   (a1)+,%2        ;  8
  460.         bra.s   Mul%1_done      ; 10 = 40 total for this path
  461.  
  462. Mul%1_b_is_0:                   ; 64 overhead to get here
  463.         Invert1 %2              ;  8
  464.         bra.s   Mul%1_done      ; 10 = 82 total for this path
  465.         endm
  466.  
  467.         MultAux 1,d4
  468.         MultAux 2,d7
  469.         MultAux 3,d5
  470.         MultAux 4,d6
  471.  
  472.         MultAux 5,d4
  473.  
  474.         xdef    _Idea
  475.         xdef    _Idea2
  476. _Idea:
  477. _Idea2:
  478.         move.l  4(sp),a0        ;  16     dataIn
  479.         move.l  12(sp),a1       ;  16  32 key
  480.  
  481. ; Since I am scrupulously careful never to touch the high halves of
  482. ; d2..d7, I only need to save the low halves.
  483.         movem.w d2-d7,-(sp)     ;  32  68
  484.  
  485.         clr.w   d1              ;   4  72 Constant 0
  486. ; movem.w <mem>,<regs> here would sign-extend.
  487.         move.w  (a0)+,d4        ;   8  80
  488.         move.w  (a0)+,d6        ;   8  88
  489.         move.w  (a0)+,d5        ;   8  96
  490.         move.w  (a0),d7         ;   8 104
  491. ; When a1 points here, stop.  96 = 2 bytes/key * 6 keys/round * 8 rounds
  492.         lea     96(a1),a0       ;   8 112
  493.  
  494. CryptLoop:
  495.         KeyMult 1,d4            ;  94     x0 *= *key++;
  496.         add.w   (a1)+,d6        ;   8 102 x1 += *key++;
  497.         add.w   (a1)+,d5        ;   8 110 x2 += *key++;
  498.         KeyMult 2,d7            ;  94 204 x3 *= *key++;
  499.  
  500.         move.w  d5,d2           ;   4 208 s2 = x2
  501.         eor.w   d4,d5           ;   4 212 x2 ^= x0
  502.         KeyMult 3,d5            ;  94 306 x2 *= *key++;
  503.         move.w  d6,d3           ;   4 310 s1 = x1;
  504.         eor.w   d7,d6           ;   4 314 x1 ^= x3;
  505.         add.w   d5,d6           ;   4 318 x1 += x2;
  506.         KeyMult 4,d6            ;  94 412 x1 *= *key++;
  507.         eor.w   d6,d4           ;   4 416 x0 ^= x1;
  508.  
  509. ;; Second unrolled copy.  Some of the first loop is postponed until after the
  510. ;; first KeyMult so that the branches there will be in short range (4 cycles).
  511.         KeyMult 5,d4
  512.  
  513.         add.w   d6,d5           ;   4 420 x2 += x1;  FIRST LOOP
  514.         eor.w   d5,d7           ;   4 424 x3 ^= x2;  FIRST LOOP
  515.         eor.w   d2,d6           ;   4 428 x1 ^= s2;  FIRST LOOP
  516.         eor.w   d3,d5           ;   4 432 x2 ^= s1;  FIRST LOOP
  517.  
  518.         add.w   (a1)+,d6
  519.         add.w   (a1)+,d5
  520.  
  521. ;; This code logically belongs after the KeyMult, but is moved up so that
  522. ;; the branches to MultAux will stay in short branch range.
  523.         move.w  d5,d2
  524.         eor.w   d4,d5
  525.         move.w  d6,d3
  526.  
  527.         KeyMult 6,d7
  528.  
  529.         KeyMult 7,d5
  530.         eor.w   d7,d6
  531.         add.w   d5,d6
  532.         KeyMult 8,d6
  533.         add.w   d6,d5
  534.         eor.w   d6,d4
  535.         eor.w   d5,d7
  536.         eor.w   d2,d6
  537.         eor.w   d3,d5           ; 432 864
  538.  
  539.         cmp.l   a0,a1           ;   6 870
  540.         bne     CryptLoop       ;  10 880
  541.                                 ;   2 114 -> From top, if expired
  542.         KeyMult 9,d4            ;  94 208 x0 *= *key++;
  543.         add.w   (a1)+,d5        ;   8 216 x2 += *key++;
  544.         add.w   (a1)+,d6        ;   8 224 x1 += *key++;
  545.         KeyMult 10,d7           ;  94 318 x3 *= *key++;
  546.  
  547.         move.l  20(a7),a0       ;  16 334 6 regs(12) + retaddr(4) + arg 1(4)
  548.         movem.w d4-d7,(a0)      ;  24 358 Store x0,x2,x1,x3
  549. ; movem.w <mem>,<regs> sign-extends, which is not what we want...
  550.         move.w  (sp)+,d2        ;   8 366
  551.         move.w  (sp)+,d3        ;   8 374
  552.         move.w  (sp)+,d4        ;   8 382
  553.         move.w  (sp)+,d5        ;   8 390
  554.         move.w  (sp)+,d6        ;   8 398
  555.         move.w  (sp)+,d7        ;   8 406
  556.         rts                     ;  16 422
  557.  
  558.         MultAux 6,d7
  559.         MultAux 7,d5
  560.         MultAux 8,d6
  561.  
  562.         MultAux 9,d4
  563.         MultAux 10,d7
  564.  
  565. ; 422 + 4 * 880 = 3942 cycles per block, or 492.75 cycles per byte.
  566. ; At 7159090 Hz, that's 1816.11 blocks per second, or 14528.8
  567. ; bytes per second.
  568.  
  569. ; End of Idea
  570.  
  571. ;; For reference, here's the original source:
  572.  
  573. ; void  Idea(u_int16 *dataIn, u_int16 *dataOut, u_int16 *key)
  574. ; {
  575. ;   register u_int16 round, x0, x1, x2, x3, s1, s2;
  576. ;
  577. ;   x0 = *dataIn++; x1 = *dataIn++; x2 = *dataIn++; x3 = *dataIn;
  578. ;
  579. ;   for (round = nofRound; round > 0; round--) {
  580. ;     x0 = Mul(x0, *key++);
  581. ;     x1 += *key++;
  582. ;     x2 += *key++;
  583. ;     x3 = Mul(x3, *key++);
  584. ;
  585. ;     s1 = x1;  s2 = x2;
  586. ;     x2 ^= x0;
  587. ;     x2 = Mul(x2, *key++);
  588. ;     x1 ^= x3;
  589. ;     x1 += x2;
  590. ;     x1 = Mul(x1, *key++);
  591. ;     x2 += x1;
  592. ;
  593. ;     x0 ^= x1;
  594. ;     x3 ^= x2;
  595. ;
  596. ;     x1 ^= s2;
  597. ;     x2 ^= s1;
  598. ;   }
  599. ;   *(dataOut++) = Mul(x0, *key++);
  600. ;   *(dataOut++) = x2 + *key++;
  601. ;   *(dataOut++) = x1 + *key++;
  602. ;   *(dataOut) = Mul(x3, *key);
  603. ; } /* Idea */
  604.  
  605. ;;;
  606. ;;; This expands a user key to a full idea key, copying the 128-bit block
  607. ;;; with a 25-bit rotation each time.
  608. ;;;
  609.  
  610. ; void ExpandUserKey(uint16 userKey[8], uint16 key[52])
  611. ; Expand an 8-word (16-byte) user key into a 52-word (104-byte)
  612. ; working key, by rotating the 128-bit big-endian key left 25
  613. ; bits and storing the result in the next 8 words, successively.
  614.  
  615. ; 1306 cycles total = (@ 7159090 Hz) 182.425 us
  616.  
  617. ; Rotate a/b/c/d left 25 bits, by rotating right 7 and shifting
  618. ; down 1 register
  619.  
  620. shdown  macro   ; a, b, c, d, e, temp, const
  621.                         ; aaaa bbbb cccc dddd ____ ____
  622.         move.l  %1,%5   ; aaaa bbbb cccc dddd aaaa ____  4
  623.         and.w   %7,%1   ; __0a bbbb cccc dddd aaaa ____  4   8
  624.         eor.w   %1,%5   ; __0a bbbb cccc dddd aaa0 ____  4  12
  625.  
  626.         move.w  %4,%6   ; __0a bbbb cccc dddd aaa0 __dd  4  16
  627.         and.w   %7,%6   ; __0a bbbb cccc dddd aaa0 __0d  4  20
  628.         eor.w   %6,%4   ; __0a bbbb cccc ddd0 aaa0 __0d  4  24
  629.         or.w    %6,%5   ; __0a bbbb cccc ddd0 aaad __0d  4  28
  630.         ror.l   #7,%5   ; __0a bbbb cccc ddd0 daaa __0d 22  50
  631.  
  632.         move.w  %3,%6   ; __0a bbbb cccc ddd0 daaa __cc  4  54
  633.         and.w   %7,%6   ; __0a bbbb cccc ddd0 daaa __0c  4  58
  634.         eor.w   %6,%3   ; __0a bbbb ccc0 ddd0 daaa __0c  4  62
  635.         or.w    %6,%4   ; __0a bbbb ccc0 dddc daaa __0c  4  66
  636.         ror.l   #7,%4   ; __0a bbbb ccc0 cddd daaa __0c 22  88
  637.  
  638.         move.w  %2,%6   ; __0a bbbb ccc0 cddd daaa __bb  4  92
  639.         and.w   %7,%6   ; __0a bbbb ccc0 cddd daaa __0b  4  96
  640.         eor.w   %6,%2   ; __0a bbb0 ccc0 cddd daaa __0b  4 100
  641.         or.w    %6,%3   ; __0a bbb0 cccb cddd daaa __0b  4 104
  642.         ror.l   #7,%3   ; __0a bbb0 bccc cddd daaa __0b 22 126
  643.  
  644.         or.w    %1,%2   ; __0a bbba bccc cddd daaa __0b  4 130
  645.         ror.l   #7,%2   ; __0a abbb bccc cddd daaa __0b 22 152
  646.  
  647. ; Rotate a/b/c/d left 25 bits, result in e/f/a/b.
  648.         endm
  649.  
  650. shup    macro   ; e, f, a, b, c, d, const
  651.                         ; ____ ____ aaaa bbbb cccc dddd
  652.         move.l  %4,%1   ; bbbb ____ aaaa bbbb cccc dddd  4
  653.         and.w   %7,%4   ; bbbb ____ aaaa __0b cccc cccc  4   8
  654.         eor.w   %4,%1   ; bbb0 xxxx aaaa __0b cccc dddd  4  12
  655.  
  656.         move.l  %5,%2   ; bbb0 cccc aaaa __0b cccc dddd  4  16
  657.         and.w   %7,%5   ; bbb0 cccc aaaa __0b __0c dddd  4  20
  658.         eor.w   %5,%2   ; bbb0 ccc0 aaaa __0b __0c dddd  4  24
  659.         or.w    %4,%2   ; bbb0 cccb aaaa __0b __0c dddd  4  28
  660.         ror.l   #7,%2   ; bbb0 bccc aaaa __0b __0c dddd 22  50
  661.  
  662.         move.l  %3,%4   ; bbb0 bccc aaaa aaaa __0c dddd  4  54
  663.         and.w   %7,%3   ; bbb0 bccc __0a aaaa __0c dddd  4  58
  664.         eor.w   %3,%4   ; bbb0 bccc __0a aaa0 __0c dddd  4  62
  665.         or.w    %3,%1   ; bbba bccc __0a aaa0 __0c dddd  4  66
  666.         ror.l   #7,%1   ; abbb bccc __0a aaa0 __0c dddd 22  88
  667.  
  668.         move.l  %6,%3   ; abbb bccc dddd aaa0 __0c dddd  4  92
  669.         and.w   %7,%6   ; abbb bccc dddd aaa0 __0c __0d  4  96
  670.         eor.w   %6,%3   ; abbb bccc ddd0 aaa0 __0c __0d  4 100
  671.         or.w    %5,%3   ; abbb bccc dddc aaa0 __0c __0d  4 104
  672.         ror.l   #7,%3   ; abbb bccc cddd aaa0 __0c __0d 22 126
  673.  
  674.         or.w    %6,%4   ; abbb bccc cddd aaad __0c __0d  4 130
  675.         ror.l   #7,%4   ; abbb bccc cddd daaa __0c __0d 22 152
  676.  
  677.         endm
  678.  
  679.         xdef    _ExpandUserKey
  680.         xdef    _ExpandUserKey2
  681. _ExpandUserKey:
  682. _ExpandUserKey2:
  683.         move.l  4(sp),a0        ; UserKey                16
  684.         move.l  8(sp),a1        ; Key                    16   32
  685.         movem.l d2-d5,-(sp)     ;                        40   72
  686.         movem.l (a0),d0-d3      ; Fetched into d0-d3     44  116
  687.         move.l  d7,a0           ;                         4  120
  688.         moveq   #127,d7         ;                         4  124
  689.  
  690.         movem.l d0-d3,(a1)      ; Store words 0..7       40  164
  691.  
  692.         shdown  d0,d1,d2,d3,d4,d5,d7    ;               152  318
  693.         movem.l d1-d4,16(a1)    ; Store words 8..15      44  360
  694.  
  695.         shdown  d1,d2,d3,d4,d5,d0,d7    ;               152  512
  696.         movem.l d2-d5,32(a1)    ; store words 16..23     44  556
  697.  
  698.         shup    d0,d1,d2,d3,d4,d5,d7    ;               152  708
  699.         movem.l d0-d3,48(a1)    ; Store words 24..31     44  752
  700.  
  701.         shdown  d0,d1,d2,d3,d4,d5,d7    ;               152  904
  702.         movem.l d1-d4,64(a1)    ; Store words 32..39     44  948
  703.  
  704.         shdown  d1,d2,d3,d4,d5,d0,d7    ;               152 1100
  705.         movem.l d2-d5,80(a1)    ; store words 40..47     44 1144
  706.  
  707. ; We only need two longwords this iteration
  708. ;                        (d2   d3   d4   d5)
  709.  
  710.                         ; aaaa bbbb cccc dddd
  711.         and.w   d7,d2   ; __0a bbbb cccc dddd             4 1148
  712.  
  713.         move.w  d3,d5   ; __0a bbbb cccc __bb             4 1152
  714.         and.w   d7,d5   ; __0a bbbb cccc __0b             4 1156
  715.         eor.w   d5,d3   ; __0a bbb0 cccc __0b             4 1160
  716.         or.w    d2,d3   ; __0a bbba cccc __0b             4 1164
  717.         ror.l   #7,d3   ; __0a abbb cccc __0b            22 1186
  718.  
  719.         not.w   d7      ;                                 4 1190
  720.         and.w   d7,d4   ; __0a abbb ccc0 __0b             4 1194
  721.         or.w    d5,d4   ; __0a abbb cccb __0b             4 1198
  722.         ror.l   #7,d4   ; __0a abbb bccc __0b            22 1220
  723.  
  724.         movem.l d3-d4,96(a1)    ; store words 48..51     28 1248
  725.  
  726.         move.l  a0,d7   ;                                 4 1252
  727.         movem.l (sp)+,d2-d5     ;                        44 1296
  728.         rts             ;                                10 1306
  729.  
  730. ;;;
  731. ;;; This section inverts keys
  732. ;;; First, the code to find a multiplicative inverse
  733. ;;;
  734.  
  735. ; Set up the registers for InvCore
  736. InvPrep macro   ; %1 = in.l, %2 = temp.l, %3 = out.w
  737.         move.l  %1,%2
  738.         move.w  %2,%3
  739.  
  740.         endm
  741.  
  742. ; Note: this expects %1 to be set to the input value (high 16 bits zero!),
  743. ; and be non-zero, %2 to  be set to 0x10001, and %3 to be set to 1.  It
  744. ; returns the multiplicative inverse of %1 in %3.  It does not affect the
  745. ; high words of %1, %3 and %4.  %2 and %5 have all 32 bits trashed.
  746.  
  747. InvCore macro   ; %1 = in.l,   %2 = mod.l,  %3 = out.w,
  748.                 ; %4 = temp.w, %5 = temp.l, %6 = #1.w
  749. ;iter1\@:
  750.         divu    %1,%2
  751.         bvs     Out1\@  ; If ovfl, input=1, so inverse = 1 (in %3).
  752.         move.w  %2,%4   ; t0 = t0 + t1 * q = 0 + 1 * q = q
  753. ;       mulu    %3,%5   ; If we had copied to d4, we would have done this...
  754. ;       add.w   %5,%4   ; But since we know d0=1 and d2=0, we can skip it
  755.         clr.w   %2
  756.         swap    %2
  757. ;       cmp.w   #1,%2
  758.         cmp.w   %3,%2   ; Since %3 = 1
  759.         beq     Out2\@  ; remainder = 1, so quit - inverse in -%5
  760.  
  761. InvLoop\@:
  762. ;iter2\@:
  763.         divu    %2,%1
  764.         move.w  %1,%5
  765.         mulu    %4,%5
  766.         add.w   %5,%3
  767.         clr.w   %1
  768.         swap    %1
  769.         cmp.w   %6,%1
  770.         beq     Out1\@  ; remainder = 1, so quit - inverse in %3
  771. ;iter3\@:
  772.         divu    %1,%2
  773.         move.w  %2,%5
  774.         mulu    %3,%5
  775.         add.w   %5,%4
  776.         clr.w   %2
  777.         swap    %2
  778.         cmp.w   %6,%2
  779. ;       beq     Out2\@  ; remainder = 1, so quit - inverse in -%4
  780. ;       bra     InvLoop\@
  781.         bne     InvLoop\@
  782.  
  783. Out2\@:                 ; Inverse in -%4
  784.         move.w  %6,%3
  785.         sub.w   %4,%3
  786. Out1\@:                 ; Inverse in %3
  787.  
  788.         endm
  789.  
  790. InputZero:
  791.         moveq   #0,d0
  792.         rts
  793.  
  794.         xdef    _MulInv
  795.         xdef    _MulInv2
  796. _MulInv:
  797. _MulInv2:
  798.         moveq   #0,d1
  799.         move.w  4(sp),d1
  800.         beq     InputZero
  801.         move.l  d2,a0
  802.         move.w  d3,-(sp)
  803.         move.l  d4,a1
  804.  
  805.         moveq   #1,d0
  806.         move.l  #$10001,d3
  807.  
  808.         InvCore d1,d3,d0,d2,d4,#1
  809.  
  810.         move.l  a1,d4
  811.         move.w  (sp)+,d3
  812.         move.l  a0,d2
  813.  
  814.         rts
  815. MulInvEnd:
  816.  
  817. ; Because it's legal to invert a key on top of itself, we push the inverted
  818. ; key onto the stack and then copy it to the destination at the end.
  819.  
  820.         xdef    _InvertIdeaKey:
  821.         xdef    _InvertIdeaKey2:
  822. _InvertIdeaKey:
  823. _InvertIdeaKey2:
  824.         move.l  4(sp),a0        ; Source
  825.         move.l  8(sp),a1        ; Dest pointer
  826.         movem.l d2-d7,-(sp)
  827.  
  828.         move.l  #$10001,d7
  829.  
  830.         move.l  (a0)+,d0
  831.         move.l  (a0)+,d1
  832.  
  833.         moveq   #0,d3           ; Clear high half of d3
  834.         move.w  d1,d3
  835.         beq     IIKzero1
  836.         InvPrep d7,d4,d1
  837.         InvCore d3,d4,d1,d5,d6,d7
  838. IIKzero1:
  839.         swap    d1
  840.         neg.w   d1
  841.         swap    d1
  842.  
  843.         move.l  d1,-(sp)
  844.  
  845.         swap    d0
  846.         move.w  d0,d3
  847.         beq     IIKzero2
  848.         InvPrep d7,d4,d0
  849.         InvCore d3,d4,d0,d5,d6,d7
  850. IIKzero2:
  851.         swap    d0
  852.         neg.w   d0
  853.  
  854.         move.l  d0,-(sp)
  855.  
  856.         moveq   #nofRound-2,d2
  857.         bra     IIKloop
  858.  
  859. IIKzero3:       ; Located here to be in short branch range
  860.                 ; (saves 4*7 = 28 cycles; costs one branch = 10 cycles)
  861. ; d1.w == 0; d0.w is unknown
  862.         move.w  d0,d4
  863.         beq     IIKzero3a
  864.         InvPrep d7,d5,d1
  865.         InvCore d4,d5,d1,d0,d6,d7
  866.         clr.w   d0
  867.         bra     IIKzero3a
  868.  
  869. IIKzero4:
  870. ; d1.w != 0; d0.w == 0
  871.         clr.w   d1
  872.         bra     IIKzero4a
  873.  
  874. IIKloop:
  875.         move.l  (a0)+,-(sp)
  876.         move.l  (a0)+,d0
  877.         move.l  (a0)+,d1
  878.  
  879.         neg.w   d0
  880.         swap    d0
  881.         move.w  d1,d3
  882.         beq     IIKzero3
  883.         move.w  d0,d4
  884.         beq     IIKzero4
  885.         InvPrep d7,d5,d1
  886.         InvCore d4,d5,d1,d0,d6,d7
  887. IIKzero4a:
  888.         InvPrep d7,d4,d0
  889.         InvCore d3,d4,d0,d5,d6,d7
  890. IIKzero3a:
  891.         move.l  d0,-(sp)
  892.         swap    d1
  893.         neg.w   d1
  894.         move.l  d1,-(sp)
  895.  
  896.         dbra    d2,IIKloop
  897.  
  898.         move.l  (a0)+,d2
  899.         move.l  (a0)+,d0
  900.         move.l  (a0)+,d1
  901.  
  902.         move.w  d1,d3
  903.         beq     IIKzero5
  904.         InvPrep d7,d4,d1
  905.         InvCore d3,d4,d1,d5,d6,d7
  906. IIKzero5:
  907.         swap    d1
  908.         neg.w   d1
  909.         swap    d1
  910.  
  911.         swap    d0
  912.         move.w  d0,d3
  913.         beq     IIKzero6
  914.         InvPrep d7,d4,d0
  915.         InvCore d3,d4,d0,d5,d6,d7
  916. IIKzero6:
  917.         swap    d0
  918.         neg.w   d0
  919.  
  920. ;       move.l  d0,(a1)+        ; Install these last three longwords...NOT
  921. ;       move.l  d1,(a1)+        ; Merge this with the movem below.
  922. ;       move.l  d2,(a1)+
  923.                                 ; 104 bytes of key = 26 longs = 9+9+8
  924.         movem.l (sp)+,d3-d7/a0
  925.         movem.l d0-d7/a0,(a1)   ; 9 longs
  926.         movem.l (sp)+,d0-d7/a0
  927.         movem.l d0-d7/a0,36(a1) ; 9 longs
  928.         movem.l (sp)+,d0-d7
  929.         movem.l d0-d7,72(a1)    ; 8 longs
  930.  
  931.         movem.l (sp)+,d2-d7     ; Retrieve registers
  932.         rts
  933.  
  934. InvertIdeaKeyEnd:
  935.  
  936. ;; And for reference, the original code...
  937.  
  938. ; void InvertIdeaKey( u_int16 *key, u_int16 *invKey)
  939. ; {
  940. ;   register int  i;
  941. ;   KeyT(dk);
  942. ;
  943. ;   dk[nofKeyPerRound * nofRound + 0] = MulInv(*key++);
  944. ;   dk[nofKeyPerRound * nofRound + 1] = (addMod - *key++) & ones;
  945. ;   dk[nofKeyPerRound * nofRound + 2] = (addMod - *key++) & ones;
  946. ;   dk[nofKeyPerRound * nofRound + 3] = MulInv(*key++);
  947. ;   for (i = nofKeyPerRound * (nofRound - 1); i >= 0; i -= nofKeyPerRound) {
  948. ;     dk[i + 4] = *key++;
  949. ;     dk[i + 5] = *key++;
  950. ;     dk[i + 0] = MulInv(*key++);
  951. ;     if (i > 0) {
  952. ;       dk[i + 2] = (addMod - *key++) & ones;
  953. ;       dk[i + 1] = (addMod - *key++) & ones;
  954. ;     } else {
  955. ;       dk[i + 1] = (addMod - *key++) & ones;
  956. ;       dk[i + 2] = (addMod - *key++) & ones;
  957. ;     }
  958. ;     dk[i + 3] = MulInv(*key++);
  959. ;   }
  960. ;   for (i = 0; i < keyLen; i++)
  961. ;     invKey[i] = dk[i];
  962. ; } /* InvertIdeaKey */
  963.  
  964.